//! 数据库填充模块
//! 
//! 自动化数据库表的创建和数据填充，支持Schema推断和自动匹配

use std::collections::HashMap;
use serde_json::Value;
use crate::error::{DataForgeError, Result};

pub mod connection;
pub mod filling;
pub mod batch;
pub mod mysql;
pub mod generators;
pub mod utils;

pub use connection::*;
pub use filling::*;
pub use batch::*;
pub use mysql::*;
pub use utils::*;

use crate::db::schema::{DataType, TableSchema};

/// 数据库填充配置
#[derive(Debug, Clone)]
pub struct FillingConfig {
    /// 批量插入大小
    pub batch_size: usize,
    /// 是否启用事务
    pub use_transaction: bool,
    /// 超时时间（秒）
    pub timeout_seconds: u64,
    /// 重试次数
    pub retry_count: usize,
}

impl Default for FillingConfig {
    fn default() -> Self {
        Self {
            batch_size: 1000,
            use_transaction: true,
            timeout_seconds: 30,
            retry_count: 3,
        }
    }
}

/// 数据库填充统计
#[derive(Debug, Clone, Default)]
pub struct FillingStats {
    /// 总插入行数
    pub total_rows: usize,
    /// 成功插入行数
    pub successful_rows: usize,
    /// 失败插入行数
    pub failed_rows: usize,
    /// 处理时间（毫秒）
    pub processing_time_ms: u64,
    /// 平均插入速度（行/秒）
    pub rows_per_second: f64,
}

impl FillingStats {
    /// 计算插入速度
    pub fn calculate_speed(&mut self) {
        if self.processing_time_ms > 0 {
            self.rows_per_second = (self.successful_rows as f64 * 1000.0) / self.processing_time_ms as f64;
        }
    }
}

/// 数据库填充器接口
pub trait DatabaseFiller {
    /// 创建表
    fn create_table(&mut self, schema: &TableSchema) -> Result<()>;
    
    /// 插入数据
    fn insert_data(&mut self, table_name: &str, data: Vec<HashMap<String, Value>>) -> Result<()>;
    
    /// 批量插入数据
    fn batch_insert(&mut self, table_name: &str, data: Vec<HashMap<String, Value>>) -> Result<()>;
    
    /// 获取统计信息
    fn get_stats(&self) -> FillingStats;
    
    /// 清空表
    fn truncate_table(&mut self, table_name: &str) -> Result<()>;
    
    /// 删除表
    fn drop_table(&mut self, table_name: &str) -> Result<()>;
}

/// 通用数据库填充器
pub struct GenericFiller {
    #[allow(dead_code)]
    config: FillingConfig,
    #[allow(dead_code)]
    stats: FillingStats,
    #[allow(dead_code)]
    connection_string: String,
}

impl GenericFiller {
    /// 创建新的填充器
    pub fn new(connection_string: String, config: FillingConfig) -> Self {
        Self {
            config,
            stats: FillingStats::default(),
            connection_string,
        }
    }

    /// 验证数据类型
    fn validate_data_type(&self, value: &Value, data_type: &DataType) -> Result<()> {
        match (value, data_type) {
            (Value::String(_), DataType::String { .. }) => Ok(()),
            (Value::Number(n), DataType::Integer { .. }) if n.is_i64() => Ok(()),
            (Value::Number(n), DataType::Float { .. }) if n.is_f64() => Ok(()),
            (Value::Bool(_), DataType::Boolean) => Ok(()),
            (Value::String(_), DataType::DateTime { .. }) => Ok(()),
            (Value::String(_), DataType::Date { .. }) => Ok(()),
            (Value::String(_), DataType::Time { .. }) => Ok(()),
            (Value::String(_), DataType::Uuid) => Ok(()),
            (Value::String(_), DataType::Email) => Ok(()),
            (Value::String(_), DataType::Phone { .. }) => Ok(()),
            (Value::String(_), DataType::Url) => Ok(()),
            (_, DataType::Json) => Ok(()),
            _ => Err(DataForgeError::validation(&format!(
                "Data type mismatch: expected {:?}, got {:?}", 
                data_type, value
            ))),
        }
    }

    /// 验证数据行
    pub fn validate_row(&self, row: &HashMap<String, Value>, schema: &TableSchema) -> Result<()> {
        for field in &schema.fields {
            if let Some(value) = row.get(&field.name) {
                self.validate_data_type(value, &field.data_type)?;
            } else if !field.constraints.nullable {
                return Err(DataForgeError::validation(&format!(
                    "Required field '{}' is missing", field.name
                )));
            }
        }
        Ok(())
    }

    /// 生成SQL创建表语句
    pub fn generate_create_table_sql(&self, schema: &TableSchema) -> String {
        let mut sql = format!("CREATE TABLE {} (\n", schema.name);
        
        let field_definitions: Vec<String> = schema.fields.iter().map(|field| {
            let mut def = format!("  {} {}", field.name, self.data_type_to_sql(&field.data_type));
            
            if !field.constraints.nullable {
                def.push_str(" NOT NULL");
            }
            
            if field.constraints.unique {
                def.push_str(" UNIQUE");
            }
            
            if let Some(default) = &field.constraints.default {
                def.push_str(&format!(" DEFAULT {}", self.value_to_sql(default)));
            }
            
            def
        }).collect();
        
        sql.push_str(&field_definitions.join(",\n"));
        
        if let Some(pk) = &schema.primary_key {
            sql.push_str(&format!(",\n  PRIMARY KEY ({})", pk.join(", ")));
        }
        
        sql.push_str("\n)");
        sql
    }

    /// 数据类型转SQL类型
    fn data_type_to_sql(&self, data_type: &DataType) -> &'static str {
        match data_type {
            DataType::String { max_length } => {
                if let Some(len) = max_length {
                    if *len <= 255 {
                        "VARCHAR(255)"
                    } else {
                        "TEXT"
                    }
                } else {
                    "TEXT"
                }
            },
            DataType::Integer { .. } => "INTEGER",
            DataType::Float { .. } => "REAL",
            DataType::Boolean => "BOOLEAN",
            DataType::DateTime { .. } => "DATETIME",
            DataType::Date { .. } => "DATE",
            DataType::Time { .. } => "TIME",
            DataType::Uuid => "VARCHAR(36)",
            DataType::Email => "VARCHAR(255)",
            DataType::Phone { .. } => "VARCHAR(20)",
            DataType::Url => "VARCHAR(2048)",
            DataType::Json => "JSON",
            DataType::Enum { .. } => "VARCHAR(50)",
            DataType::Array { .. } => "JSON",
            DataType::Object { .. } => "JSON",
            DataType::Custom { .. } => "TEXT",
        }
    }

    /// 值转SQL字符串
    fn value_to_sql(&self, value: &Value) -> String {
        match value {
            Value::String(s) => format!("'{}'", s.replace("'", "''")),
            Value::Number(n) => n.to_string(),
            Value::Bool(b) => if *b { "TRUE" } else { "FALSE" }.to_string(),
            Value::Null => "NULL".to_string(),
            _ => format!("'{}'", value.to_string().replace("'", "''")),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::db::schema::FieldConstraints;
    use crate::FieldSchema;
    use super::*;

    #[test]
    fn test_filling_config_default() {
        let config = FillingConfig::default();
        assert_eq!(config.batch_size, 1000);
        assert!(config.use_transaction);
        assert_eq!(config.timeout_seconds, 30);
        assert_eq!(config.retry_count, 3);
    }

    #[test]
    fn test_filling_stats() {
        let mut stats = FillingStats {
            total_rows: 1000,
            successful_rows: 950,
            failed_rows: 50,
            processing_time_ms: 1000,
            rows_per_second: 0.0,
        };
        
        stats.calculate_speed();
        assert_eq!(stats.rows_per_second, 950.0);
    }

    #[test]
    fn test_validate_data_type() {
        let filler = GenericFiller::new("test".to_string(), FillingConfig::default());
        
        let string_value = Value::String("test".to_string());
        let string_type = DataType::String { max_length: Some(255) };
        assert!(filler.validate_data_type(&string_value, &string_type).is_ok());
        
        let number_value = Value::Number(serde_json::Number::from(42));
        let int_type = DataType::Integer { min: None, max: None };
        assert!(filler.validate_data_type(&number_value, &int_type).is_ok());
    }

    #[test]
    fn test_generate_create_table_sql() {
        let filler = GenericFiller::new("test".to_string(), FillingConfig::default());
        
        let schema = TableSchema {
            name: "users".to_string(),
            fields: vec![
                FieldSchema {
                    name: "id".to_string(),
                    data_type: DataType::Integer { min: None, max: None },
                    constraints: FieldConstraints {
                        nullable: false,
                        unique: true,
                        default: None,
                        pattern: None,
                        min: None,
                        max: None,
                    },
                    description: None,
                    generator_config: None,
                    generator_type: None,
                },
                FieldSchema {
                    name: "name".to_string(),
                    data_type: DataType::String { max_length: Some(100) },
                    constraints: FieldConstraints {
                        nullable: false,
                        unique: false,
                        default: None,
                        pattern: None,
                        min: None,
                        max: None,
                    },
                    description: None,
                    generator_config: None,
                    generator_type: None,
                },
            ],
            primary_key: Some(vec!["id".to_string()]),
            indexes: vec![],
            description: None,
        };
        
        let sql = filler.generate_create_table_sql(&schema);
        assert!(sql.contains("CREATE TABLE users"));
        assert!(sql.contains("id INTEGER NOT NULL UNIQUE"));
        assert!(sql.contains("name VARCHAR(255) NOT NULL"));
        assert!(sql.contains("PRIMARY KEY (id)"));
    }
}